As a general rule, I have found that composition is more important than inheritance in software design. Just look around you – how many things do you see that are related to each other by inheritance? A lot fewer than the number of things that are related to each other by composition, I suspect.
You may be reading this in some type of office. If that is the case, around you will be chairs, tables, lamps, staplers, et.al. Although inheritance can be found anywhere if you look hard enough, for most practical purposes there is no inheritance among the objects of an office. From what I have seen (in a design career spanning database management systems, electronic CAD, knowledge management systems, electronic health record systems, and systems administration software) you will spend a lot more time composing software out of various different types of modules than you will spend in creating more specialized classes of existing software. For that is what inheritance buys you in software design – the ability to have ever-more specialized classes and behaviors for your objects.
CPAN is a prime example of this. If inheritance was as important in design as generally seems to be believed, then CPAN would consist mostly of derived classes, with only a relatively small number of base classes. Instead, CPAN is made up of mostly unrelated (by inheritance) classes.
Polymorphism is useful only when you have a subclass – a class that has inherited from a parent class. What I seem to see more often in practice is interfaces – objects with multiple unrelated (by inheritance) sets of behaviors. In a dog behavior simulation, a pet dog IS-A dog that IS-ALSO a pet. For mammalian pets, the behaviors of different species of pets are closer to each other in a lot of ways than to the behaviors of those mammals in the wild (interfaces vs. inheritance).
To look at the question taxonomically, inheritance and polymorphism are most advantageous when your Tree of Domain Objects is relatively deep but narrow. With a wide and shallow Tree of Domain Objects, only a few of your classes will be related by inheritance, so polymorphism will be of lesser value than is generally perceived. In my experience, wide and shallow Trees of Domain Objects seem to be the common case. Polymorphism does solve the otherwise nasty problem of setting up different behaviors for related objects in a clean, non-brittle fashion (think of many large switch statements that must be modified each time you create a new class...)
So if modules don't inherit from each other (inheritance), and code doesn't morph into the modules you need (polymorphism), then how do you usually build your modules? By composing them (composition), as you have guessed by this point. One beautiful aspect of CPAN is that there are so many different modules to go into a composition (10,000+ last I knew).
This doesn't mean that inheritance is useless – far from it. It just means (IMHO) you will end up using a lot more composition than inheritance and polymorphism. Take, for example, a desktop GUI application for automatically building written group status reports from written status reports by individuals. Inheritance and polymorphism will be used in the GUI, but a storage API like DBI is effectively much more a case of interfaces than inheritance (PostgreSQL vs. Oracle vs. flat files vs. ...), and the main classes of objects (people, groups, configurations, and report text) bear little inheritable relationship to each other.
One area where I haven't done much software engineering is the mega-system: 1M+ LOC in a single system. Maybe this is where inheritance and polymorphism get used as the main design techniques – I simply do not know.
I think this is a contrarian position to the current received wisdom, so I welcome the comments of those who are better experienced than I am.
(P.S. Why am I talking about Composition instead of Encapulation? Because (IMHO) encapsulation is of greatest use only when it serves the purpose of composition – plus, that's the way I often think about software design, as a series of compositions.)
If inheritance was as important in design as generally seems to be believed, then CPAN would consist mostly of derived classes, with only a relatively small number of base classes.
Perhaps you would, if CPAN modules generally had good design (I'm not willing to make that assumption in general) or if module authors were truly egoless programmers (I point you to templating systems, argument processing modules, web frameworks, class creation modules...).
Polymorphism is useful only when you have a subclass...
Untrue. Allomorphism is polymorphic equivalence between two entities unrelated by inheritance and it works.
Perhaps the worst sin of most OO teachings is that they conflate inheritance with polymorphism, as if inheritance were important and polymorphism merely a side effect.
Re:Disentangle Polymorphism and Inheritance!
malte on 2007-02-10T10:15:36
Very True. JavaScript and other prototype-based languages are good examples of languages that implement a very extreme form of polymorphism without even supporting language-level inheritance.